import { HierarchyNode } from 'd3';
import { Fragment, useEffect, useRef, useState } from 'react';
import arrow from './images/arrow.svg';

import './planNode.less';
import { NodeProp, NodeStatusEnum } from './utils/enums';
import { formatNumber, keysToString, sortKeys } from './utils/help';
import { Node } from './utils/interfaces';

const colorLists = [
  '#117DF1', '#F2A780', '#583C2A', '#B5AA54', '#118A96', '#E2B0A8', '#26DBEC', '#848080',
  '#F36F1C', '#F9E875', '#1F88B9', '#F5BE85', '#3B90DF', '#067EA8', '#64D3F1', '#80A2C4',
  '#F7D598', '#CFB994', '#E0BEA4', '#D9C48C', '#D4B071', '#868877', '#948B72', '#A3D4D6',
  '#D49CA4', '#D75C68', '#A4445C', '#C89C8C', '#64D3F1', '#F6A78A', '#E4BCCA', '#BC6E6B',
  '#E3DBB7', '#ECCC9E', '#BFBEBA', '#F28E1D', '#AC8648', '#887D77', '#5491B3', '#049FFA',
  '#466A99', '#5C87B3', '#E3A30D', '#2B67BC', '#72A0BD', '#5A8CC4', '#0496E2', '#749C64',
  '#FAD4A8', '#74B4E3'
]

function RelaHeader(props: {
  node: any;
  className: string;
  showDetails: boolean;
}) {
  const { node, className, showDetails } = props;
  // all undefined properties are not displayed
  if (
    !node[NodeProp.RELATION_NAME] &&
    !node[NodeProp.ALIAS] &&
    !node[NodeProp.GROUP_KEY] &&
    !node[NodeProp.SORT_KEY] &&
    !node[NodeProp.JOIN_TYPE] &&
    !node[NodeProp.INDEX_NAME] &&
    !node[NodeProp.HASH_CONDITION] &&
    !node[NodeProp.CTE_NAME]
  ) {
    return null;
  }
  return (
    <div className={className} style={{ wordBreak: 'break-word' }}>
      {node[NodeProp.RELATION_NAME] && (
        <div className={showDetails ? '' : 'line-clamp-2'}>
          <span className="text-muted">on </span>
          <span>
            {node[NodeProp.SCHEMA] && `${node[NodeProp.SCHEMA]}.`}
            {node[NodeProp.RELATION_NAME]}
          </span>
          {node[NodeProp.ALIAS] && (
            <span>
              <span className="text-muted"> as </span>
              {node[NodeProp.ALIAS]}
            </span>
          )}
        </div>
      )}
      {!node[NodeProp.RELATION_NAME] && node[NodeProp.ALIAS] && (
        <div className={showDetails ? '' : 'line-clamp-2'}>
          <span className="text-muted">on </span>
          <span
            dangerouslySetInnerHTML={{
              __html: keysToString(node[NodeProp.ALIAS] as string),
            }}
          ></span>
        </div>
      )}
      {node[NodeProp.GROUP_KEY] && (
        <div className={showDetails ? '' : 'line-clamp-2'}>
          <span className="text-muted">by </span>
          <span
            dangerouslySetInnerHTML={{
              __html: keysToString(node[NodeProp.GROUP_KEY] as string),
            }}
          ></span>
        </div>
      )}
      {node[NodeProp.SORT_KEY] && (
        <div className={showDetails ? '' : 'line-clamp-2'}>
          <span className="text-muted">by </span>
          <span
            dangerouslySetInnerHTML={{
              __html: sortKeys(
                node[NodeProp.SORT_KEY] as string[],
                node[NodeProp.PRESORTED_KEY] as string[],
              ),
            }}
          ></span>
        </div>
      )}
      {node[NodeProp.JOIN_TYPE] && (
        <div>
          {node[NodeProp.JOIN_TYPE]}
          <span className="text-muted"> join</span>
        </div>
      )}
      {node[NodeProp.INDEX_NAME] && (
        <div className={showDetails ? '' : 'line-clamp-2'}>
          <span className="text-muted">using </span>
          <span
            dangerouslySetInnerHTML={{
              __html: keysToString(node[NodeProp.INDEX_NAME] as string),
            }}
          ></span>
        </div>
      )}
      {node[NodeProp.HASH_CONDITION] && (
        <div className={showDetails ? '' : 'line-clamp-2'}>
          <span className="text-muted">on </span>
          <span
            dangerouslySetInnerHTML={{
              __html: keysToString(node[NodeProp.HASH_CONDITION] as string),
            }}
          ></span>
        </div>
      )}
      {node[NodeProp.CTE_NAME] && (
        <div>
          {/* <a
            href=""
            onClick={(e) => {
              e.preventDefault();
              e.stopPropagation();
              // centerCte();
            }}
            className="text-reset"
          >
            <span className="text-muted">CTE</span>
            {node[NodeProp.CTE_NAME]}
          </a> */}
          <span className="text-muted">CTE </span>
          {node[NodeProp.CTE_NAME]}
        </div>
      )}
    </div>
  );
}

interface IProps {
  updateNodeSize: (node: Node, size: [number, number]) => void;
  data: HierarchyNode<any>['data'];
}
function ExpandDetail(props: any) {
  const { nodeData } = props;
  const showFields = ['Total Cost', 'Startup Cost', 'Plan Width', 'Plan Rows', 'Actual Rows'];

  const d = showFields.map((fieldName) => {
    let value;
    if (fieldName === 'Plan Width') {
      value = nodeData[fieldName];
    } else {
      value = formatNumber(nodeData[fieldName]);
    }
    return {
      name: fieldName === 'Actual Rows' ? fieldName : `Estimated ${fieldName}`,
      value,
    };
  });

  return (
    <div>
      {d.map((item) => {
        return (
          <Fragment key={item.name}>
            <div className="t">{item.name}</div>
            <div className="h-text">{item.value}</div>
          </Fragment>
        );
      })}
    </div>
  );
}
export default function PlanNode(props: IProps) {
  const outerEl = useRef<HTMLDivElement>(null);
  const [showDetails, setShowDetails] = useState(false);
  
  function updateSize(node: Node) {
    const rect = outerEl.current?.getBoundingClientRect();

    if (rect) {
      props.updateNodeSize?.(node, [rect.width, rect.height]);
    }
  }

  const subPlanName = props.data[NodeProp.SUBPLAN_NAME] && (
    <div
      style={{
        position: 'fixed',
        right: 0,
        bottom: -2,
        left: 0,
        textAlign: 'center',
      }}
    >
      <b className="sub-plan-name-wrap">{props.data[NodeProp.SUBPLAN_NAME]}</b>
    </div>
  );

  function getColorById(slice: number, type?: string) {
    const index = slice % colorLists.length;

    if (type) {
      return colorLists[index] + '33';
    }
    return colorLists[index];
  }
  useEffect(() => {
    updateSize(props.data);
  },[]);

  return (
    <div
      className="chart-out-el"
      ref={outerEl}
      onClick={(e) => {
        e.preventDefault();
        e.stopPropagation();
        setShowDetails(!showDetails);
        setTimeout(() => {
          updateSize(props.data);
        });
      }}
      style={{borderColor: getColorById(props.data[NodeProp.SLICE])}}
    >
      {subPlanName}
      <div 
        className="header" 
        style={
          !props.data[NodeProp.Node_status] || props.data[NodeProp.Node_status] === NodeStatusEnum.Finished
            ? { background: getColorById(props.data[NodeProp.SLICE], 'bg') } 
            : {}
        }
      >
        <div className="top">
          <span className="top-text">{props.data['Node Type']}</span>
          <img
            className="arrow"
            src={arrow}
            alt=""
            style={{ transform: `rotate(${showDetails ? 180 : 0}deg)` }}
          />
        </div>
        <RelaHeader
          className="tip-text"
          node={props.data}
          showDetails={showDetails}
        />
        <div className="wave" >
          {
            (props.data[NodeProp.Node_status] === NodeStatusEnum.Executing 
            || props.data[NodeProp.Node_status] === NodeStatusEnum.Initialize) 
            ? (
              <div
                className="wave-animation" 
                style={{background: getColorById(props.data[NodeProp.SLICE], 'bg')}}
              >
              </div>
            ) : null
          }
        </div>
      </div>

      {showDetails && (
        <div className="detail">
          <ExpandDetail nodeData={props.data} />
        </div>
      )}
    </div>
  );
}
